package com.ant.backstage.config.shiro;

import com.alibaba.fastjson.JSONObject;
import com.ant.backstage.facade.dto.UserDTO;
import com.ant.backstage.utils.RedisUtil;
import com.ant.backstage.utils.ioc.ApplicationContextUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.springframework.cache.CacheManager;

import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * shiro +redis 缓存操作 自定义
 *
 * @author zhangyu
 * @date 2021/12/25 22:25
 * @return
 */
// 使用了shiro-redis 插件 自定义缓存代码逻辑中暂时未使用
public class ShiroCache<K, V> implements Cache<K, V> {
    private static Logger logger = LogManager.getLogger(ShiroCache.class);

    private String USER_PERISSION = "::user_perisson";

    // CacheManager注意导包
    private CacheManager springCacheManager;
    private String cacheName;

    private org.springframework.cache.Cache springCache;

    public ShiroCache(CacheManager springCacheManager, String cacheName) {
        this.springCacheManager = springCacheManager;
        this.cacheName = cacheName;
        this.springCache = springCacheManager.getCache(cacheName);
    }

    @Override
    public V get(K key) throws CacheException {
        RedisUtil redisUtil = ApplicationContextUtil.getBean(RedisUtil.class);
        logger.info("获取缓存，key：{}", key);
        org.springframework.cache.Cache.ValueWrapper valueWrapper = null;
        if (key instanceof UserDTO) {
            UserDTO user = (UserDTO) key;
            checkKey(user.getUid() + USER_PERISSION, redisUtil);
            valueWrapper = springCache.get(user.getUid() + USER_PERISSION);
        } else {
            checkKey((String) key, redisUtil);
            valueWrapper = springCache.get(key);
        }
        if (valueWrapper == null) {
            return null;
        }
        return (V) valueWrapper.get();
    }

    public Boolean checkKey(String key, RedisUtil redisUtil) {
        boolean b = redisUtil.hasKey(key);
        if (!b) {
            return null;
        }
        return true;
    }

    @Override
    public V put(K key, V value) throws CacheException {
        logger.info("放入缓存，key：{}，value：{}", key, value);
        RedisUtil redisUtil = ApplicationContextUtil.getBean(RedisUtil.class);

        try {
            SimplePrincipalCollection info = (SimplePrincipalCollection) key;
            if (info != null) {
                UserDTO userPo = (UserDTO) info.getPrimaryPrincipal();
                redisUtil.set(userPo.getUid() + USER_PERISSION, JSONObject.toJSON(value), 60 * 60);
            }
        } catch (Exception e) {
            // 认证信息，加uid前缀
            redisUtil.set((String) key, JSONObject.toJSON(value), 60 * 60);
        }
        return value;
    }

    @Override
    public V remove(K key) throws CacheException {
        if (key instanceof SimplePrincipalCollection) {
            SimplePrincipalCollection info = (SimplePrincipalCollection) key;
            if (info != null) {
                UserDTO userPo = (UserDTO) info.getPrimaryPrincipal();
                logger.info("移除权限缓存，key：{}", userPo.getUid() + USER_PERISSION);
                V oldValue = this.get((K) (userPo.getUid() + USER_PERISSION));
                springCache.evict(userPo.getUid() + USER_PERISSION);
                return oldValue;
            }
        }
        if (key instanceof UserDTO) {
            //清除用户认证信息
            UserDTO user = (UserDTO) key;
            V oldValue = this.get((K) user.getToken());
            //问题： 由于shiro默认退出时，取出的key为，realm对象 返回的SimpleAuthenticationInfo种一个参数，无法移除缓存
            logger.info("移除认证缓存，key：{}", user.getToken());
            springCache.evict((K) user.getToken());
            return oldValue;
        }
        return null;
    }

    @Override
    public void clear() throws CacheException {
        logger.info("清空缓存，cacheName：{}", cacheName);
        springCache.clear();
    }

    @Override
    public int size() {
        logger.info("缓存数量：{}", this.keys().size());
        return this.keys().size();
    }

    @Override
    public Set<K> keys() {
        Collection<String> cacheNameSet = springCacheManager.getCacheNames();
        logger.info("缓存key(CacheName)的集合：{}", String.join(",", cacheNameSet));
        return (Set<K>) cacheNameSet;
    }

    @Override
    public Collection<V> values() {
        List<V> values = this.keys().stream().map(this::get).collect(Collectors.toList());
        logger.info("缓存value的集合：{}", String.join(",", values.toString()));
        return values;
    }


}
